home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-68k-src / machines / amiga68k / libsrc / stdio / vfscanf.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  10KB  |  396 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <limits.h>
  5. #include <ctype.h>
  6. #include <math.h>
  7.  
  8. /* some macros to cut this short
  9.  * NEXT(c);     read next character
  10.  * PREV(c);     ungetc a character
  11.  * VAL(a)       leads to 1 if a is true and valid
  12.  */
  13. #define NEXT(c) ((c)=getc(stream),size++,incount++)
  14. #define PREV(c) do{if((c)!=EOF)ungetc((c),stream);size--;incount--;}while(0)
  15. #define VAL(a)  ((a)&&size<=width)
  16.  
  17. #ifdef MATH
  18. static unsigned char undef[3][sizeof(double)]= /* Undefined numeric values, IEEE */
  19. { { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
  20.   { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
  21.   { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 }  /*  NaN */
  22. };
  23. #endif
  24.  
  25. int vfscanf(FILE *stream,const char *format,va_list args)
  26. {
  27.   size_t blocks=0,incount=0;
  28.   int c=0;
  29.  
  30.   while(*format)
  31.   {
  32.     size_t size=0;
  33.  
  34.     if(*format=='%')
  35.     {
  36.       size_t width=ULONG_MAX;
  37.       char type,subtype='i',ignore=0;
  38.       const unsigned char *ptr=format+1;
  39.       size_t i;
  40.  
  41.       if(isdigit(*ptr))
  42.       { width=0;
  43.         while(isdigit(*ptr))
  44.           width=width*10+(*ptr++-'0'); }
  45.  
  46.       while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*')
  47.       { if(*ptr=='*')
  48.           ignore=1;
  49.         else
  50.           subtype=*ptr;
  51.         ptr++;
  52.       }
  53.  
  54.       type=*ptr++;
  55.  
  56.       if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[')
  57.       { do /* ignore leading whitespace characters */
  58.           NEXT(c);
  59.         while(isspace(c));
  60.         size=1; } /* The first non-whitespace character is already read */
  61.  
  62.       switch(type)
  63.       { case 'c':
  64.         { unsigned char *bp;
  65.  
  66.           if(width==ULONG_MAX) /* Default */
  67.             width=1;
  68.  
  69.           if(!ignore)
  70.             bp=va_arg(args,char *);
  71.           else
  72.             bp=NULL; /* Just to get the compiler happy */
  73.  
  74.           NEXT(c); /* 'c' did not skip whitespace */
  75.           while(VAL(c!=EOF))
  76.           { if(!ignore)
  77.               *bp++=c;
  78.             NEXT(c);
  79.           }
  80.           PREV(c);
  81.  
  82.           if(!ignore&&size)
  83.             blocks++;
  84.           break;
  85.         }
  86.         case '[':
  87.         { unsigned char *bp;
  88.           unsigned char tab[32],a,b;
  89.           char circflag=0;
  90.  
  91.           if(*ptr=='^')
  92.           { circflag=1;
  93.             ptr++; }
  94.           for(i=0;i<sizeof(tab);i++)
  95.             tab[i]=circflag?255:0;
  96.           do
  97.           { if(!*ptr)
  98.               break;
  99.             a=*ptr++;
  100.             if(*ptr=='-'&&ptr[1]>a)
  101.             { ptr++;
  102.               b=*ptr++;
  103.             }else
  104.               b=a;
  105.             for(i=a;i<=b;i++)
  106.               if(circflag)
  107.                 tab[i/8]&=~(1<<(i&7));
  108.               else
  109.                 tab[i/8]|=1<<(i&7);
  110.           }while(*ptr!=']');
  111.  
  112.           ptr++;  /*vb*/
  113.  
  114.           if(!ignore)
  115.             bp=va_arg(args,char *);
  116.           else
  117.             bp=NULL; /* Just to get the compiler happy */
  118.  
  119.           NEXT(c);
  120.           while(VAL(c!=EOF&&tab[c/8]&(1<<(c&7))))
  121.           { if(!ignore)
  122.               *bp++=c;
  123.             NEXT(c);
  124.           }
  125.           PREV(c);
  126.  
  127.           if(!ignore&&size)
  128.           { *bp++='\0';
  129.             blocks++; }
  130.           break;
  131.         }
  132.         case 's':
  133.         { unsigned char *bp;
  134.  
  135.           if(!ignore)
  136.             bp=va_arg(args,char *);
  137.           else
  138.             bp=NULL; /* Just to get the compiler happy */
  139.  
  140.           while(VAL(c!=EOF&&!isspace(c)))
  141.           { if(!ignore)
  142.               *bp++=c;
  143.             NEXT(c);
  144.           }
  145.           PREV(c);
  146.  
  147.           if(!ignore&&size)
  148.           { *bp++='\0';
  149.             blocks++; }
  150.           break;
  151.         }
  152. #ifdef MATH
  153.         case 'e':
  154.         case 'f':
  155.         case 'g':
  156.         { double v;
  157.           int ex=0;
  158.           int min=0,mine=0; /* This is a workaround for gcc 2.3.3: should be char */
  159.  
  160.           do /* This is there just to be able to break out */
  161.           {
  162.             if(VAL(c=='-'||c=='+'))
  163.             { min=c;
  164.               NEXT(c); }
  165.  
  166.             if(VAL(tolower(c)=='i')) /* +- inf */
  167.             { int d;
  168.               NEXT(d);
  169.               if(VAL(tolower(d)=='n'))
  170.               { int e;
  171.                 NEXT(e);
  172.                 if(VAL(tolower(e)=='f'))
  173.                 { v=*(double *)&undef[min=='-'];
  174.                   break; } /* break out */
  175.                 PREV(e);
  176.               }
  177.               PREV(d);
  178.             }
  179.             else if(VAL(toupper(c)=='N')) /* NaN */
  180.             { int d;
  181.               NEXT(d);
  182.               if(VAL(tolower(d)=='a'))
  183.               { int e;
  184.                 NEXT(e);
  185.                 if(VAL(toupper(e)=='N'))
  186.                 { v=*(double *)&undef[2];
  187.                   break; }
  188.                 PREV(e);
  189.               }
  190.               PREV(d);
  191.             }
  192.  
  193.             v=0.0;
  194.             while(VAL(isdigit(c)))
  195.             { v=v*10.0+(c-'0');
  196.               NEXT(c);
  197.             }
  198.  
  199.             if(VAL(c=='.'))
  200.             { double dp=0.1;
  201.               NEXT(c);
  202.               while(VAL(isdigit(c)))
  203.               { v=v+dp*(c-'0');
  204.                 dp=dp/10.0;
  205.                 NEXT(c); }
  206.               if(size==2+(min!=0)) /* No number read till now -> malformatted */
  207.               { PREV(c);
  208.                 c='.'; }
  209.             }
  210.  
  211.             if(min&&size==2) /* No number read till now -> malformatted */
  212.             { PREV(c);
  213.               c=min; }
  214.             if(size==1)
  215.               break;
  216.  
  217.             if(VAL(tolower(c)=='e'))
  218.             { int d;
  219.               NEXT(d);
  220.               if(VAL(d=='-'||d=='+'))
  221.               { mine=d;
  222.                 NEXT(d); }
  223.  
  224.               if(VAL(isdigit(d)))
  225.               { do
  226.                 { ex=ex*10+(d-'0');
  227.                   NEXT(d);
  228.                 }while(VAL(isdigit(d)&&ex<100));
  229.                 c=d;
  230.               }else
  231.               { PREV(d);
  232.                 if(mine)
  233.                   PREV(mine);
  234.               }
  235.             }
  236.             PREV(c);
  237.  
  238.             if(mine=='-')
  239.               v=v/pow(10.0,ex);
  240.             else
  241.               v=v*pow(10.0,ex);
  242.  
  243.             if(min=='-')
  244.               v=-v;
  245.  
  246.           }while(0);
  247.  
  248.           if(!ignore&&size)
  249.           { switch(subtype)
  250.             { case 'l':
  251.               case 'L':
  252.                 *va_arg(args,double *)=v;
  253.                 break;
  254.               case 'i':
  255.                 *va_arg(args,float *)=v;
  256.                 break;
  257.             }
  258.             blocks++;
  259.           }
  260.           break;
  261.         }
  262. #endif
  263.         case '%':
  264.           NEXT(c);
  265.           if(c!='%')
  266.             PREV(c); /* unget non-'%' character */
  267.           break;
  268.         case 'n':
  269.           if(!ignore)
  270.             *va_arg(args,int *)=incount;
  271.           size=1; /* fake a valid argument */
  272.           blocks++;
  273.           break;
  274.         default:
  275.         { unsigned long v=0;
  276.           int base;
  277.           int min=0;
  278.  
  279.           if(!type)
  280.             ptr--; /* unparse NUL character */
  281.  
  282.           if(type=='p')
  283.           { subtype='l'; /* This is the same as %lx */
  284.             type='x'; }
  285.  
  286.           if(VAL((c=='-'&&type!='u')||c=='+'))
  287.           { min=c;
  288.             NEXT(c); }
  289.  
  290.           if(type=='i') /* which one to use ? */
  291.           { if(VAL(c=='0')) /* Could be octal or sedecimal */
  292.             { int d;
  293.               NEXT(d); /* Get a look at next character */
  294.               if(VAL(tolower(d)=='x'))
  295.               { int e;
  296.                 NEXT(e); /* And the next */
  297.                 if(VAL(isxdigit(c)))
  298.                   type='x'; /* Is a valid x number with '0x?' */
  299.                 PREV(e);
  300.               }else
  301.                 type='o';
  302.               PREV(d);
  303.             }else if(VAL(!isdigit(c)&&isxdigit(c)))
  304.               type='x'; /* Is a valid x number without '0x' */
  305.           }
  306.  
  307.           while(type=='x'&&VAL(c=='0')) /* sedecimal */
  308.           { int d;
  309.             NEXT(d);
  310.             if(VAL(tolower(d)=='x'))
  311.             { int e;
  312.               NEXT(e);
  313.               if(VAL(isxdigit(e)))
  314.               { c=e;
  315.                 break; } /* Used while just to do this ;-) */
  316.               PREV(e);
  317.             }
  318.             PREV(d);
  319.             break; /* Need no loop */
  320.           }
  321.  
  322.           base=type=='x'||type=='X'?16:(type=='o'?8:10);
  323.           while(VAL(isxdigit(c)&&(base!=10||isdigit(c))&&(base!=8||c<='7')))
  324.           { v=v*base+(isdigit(c)?c-'0':0)+(isupper(c)?c-'A'+10:0)+(islower(c)?c-'a'+10:0);
  325.             NEXT(c);
  326.           }
  327.  
  328.           if(min&&size==2) /* If there is no valid character after sign, unget last */
  329.           { PREV(c);
  330.             c=min; }
  331.  
  332.           PREV(c);
  333.  
  334.           if(ignore||!size)
  335.             break;
  336.  
  337.           if(type=='u')
  338.             switch(subtype)
  339.             { case 'l':
  340.               case 'L':
  341.                 *va_arg(args,unsigned long *)=v;
  342.                 break;
  343.               case 'i':
  344.                 *va_arg(args,unsigned int *)=v;
  345.                 break;
  346.               case 'h':
  347.                 *va_arg(args,unsigned short *)=v;
  348.                 break;
  349.             }
  350.           else
  351.           { signed long v2;
  352.             if(min=='-')
  353.               v2=-v;
  354.             else
  355.               v2=v;
  356.             switch(subtype)
  357.             { case 'l':
  358.               case 'L':
  359.                 *va_arg(args,signed long *)=v2;
  360.                 break;
  361.               case 'i':
  362.                 *va_arg(args,signed int *)=v2;
  363.                 break;
  364.               case 'h':
  365.                 *va_arg(args,signed short *)=v2;
  366.                 break;
  367.             }
  368.           }
  369.           blocks++;
  370.           break;
  371.         }
  372.       }
  373.       format=ptr;
  374.     }else
  375.     { if(isspace(*format))
  376.       { do
  377.           NEXT(c);
  378.         while(isspace(c));
  379.         PREV(c);
  380.         size=1; }
  381.       else
  382.       { NEXT(c);
  383.         if(c!=*format)
  384.           PREV(c); }
  385.       format++;
  386.     }
  387.     if(!size)
  388.       break;
  389.   }
  390.  
  391.   if(c==EOF&&!blocks)
  392.     return c;
  393.   else
  394.     return blocks;
  395. }
  396.